package controllers.GestionTratamientoDatos.Metodos.Completacion.Metodos;

/**
 * Created with IntelliJ IDEA.
 * User: Alejandro
 * Date: 07/08/13
 * Time: 10:46 AM
 * To change this template use File | Settings | File Templates.
 */

import java.util.List;
import java.awt.Dimension;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;

import javax.management.openmbean.ArrayType;
import javax.swing.JFrame;

import controllers.GestionTratamientoDatos.Metodos.Completacion.MetodoCompletacionBase;
import models.Hidregistro;
import org.ejml.simple.SimpleMatrix;

public class Lsa extends MetodoCompletacionBase{
    public Integer nmiss = 5;
    public Integer n_interval = 7;
    //public Vector<Double> datos = new Vector<Double>();
    public Vector<Integer> indices = new Vector<Integer>();
    public Vector<Double> y = new  Vector<Double>();
    //public SimpleMatrix
    public Vector<Double> x = new Vector<Double>();
    public Vector<Double> nx = new Vector<Double>();
    //public SimpleMatrix M = new SimpleMatrix(arg0);
    public Vector<Double> data;


    //public Lsa(Vector<Double> datos){
    //  data = new Vector<Double>();
    // data= datos;

    // }

    public Lsa (Vector<Double> v){
        super(v);
    }

    @Override
    public void completar(){
       Vector<Double> resultado = run();
        setSerieVector(resultado);
    }






    public Vector<Double> run(){
        //Double[]v_ = {1.7, 1.285, 3.708, 6.001, 7.569, 10.170, 8.777};
        //Double[]vf ={1.7, 1.285,null ,null ,null ,10.170,8.777};
        //Vector<Double> datos_ = new Vector<Double>(Arrays.asList(v_));
        //Vector<Double> datosf= new Vector<Double>(Arrays.asList(vf));
        Vector<Double> datosf = getSerieVector();
      //  datosf=data;

        //System.out.println("DATA "+data);
        //System.out.println("DATOS "+datosf);
        int sized = datosf.size();
        //System.out.println(datos_);
        //System.out.println(datosf);



        //System.out.println(datos);

        Vector<Double> datos = new Vector<Double>(n_interval);
        datos = iniVector(datos);


        for(int k=0; k<sized; k++){

            Integer ind=k % n_interval;
            //System.out.println(ind);
            if (ind.equals(n_interval-1)){
                datos.set(n_interval-1,datosf.get(k));
            }
            else{
                datos.set(ind,datosf.get(k));
            }
            //System.out.println("no complete : "+datos);
            if(ind.equals(n_interval-1) && (sized-k)<n_interval){
                datos.addAll(datosf.subList(k+1, datosf.size()));
            }

            //System.out.println("complete : "+datos);
            if( ind.equals(n_interval-1)){
               // System.out.println("datos "+datos);
                Integer first_size = datos.size();
                datos = recreateData(datosf, datos, k-n_interval+1);

               // System.out.println("datos recreados "+datos);
                Integer size = datos.size();
                Integer n_faltantes = 0;
                int j=1;
                for (int i=0; i<size; i++){
                    //	System.out.println(datos.get(i));
                    if(datos.get(i)==999999){
                        n_faltantes++;

                    }
                    else{
                        indices.add(i);
                        y.add(datos.get(i));
                        j++;
                    }

                }

                //System.out.println("nfaltantes : "+n_faltantes);
                SimpleMatrix M = new SimpleMatrix(n_faltantes,indices.size());
                SimpleMatrix Mt = new SimpleMatrix(n_faltantes,indices.size());

                SimpleMatrix ny = vector2SimpleMatrix(y);

                M  = poly(n_faltantes, indices);
                //		System.out.println(M);
                Mt = M.transpose();

                //	System.out.println("M : "+M);
                //		System.out.println("Mt : "+Mt);
                SimpleMatrix v = Mt.mult(M).invert().mult(Mt).mult(ny.transpose());
                //			System.out.println("v : "+v);
                v = v.transpose();

                //		System.out.println("vt :"+v);

                v=reverse(v);

                //	System.out.println("v reverse  :"+v);

                for(int i=0; i<size; i++){
                    if(datos.get(i)==999999){
                        x.add(polyVal(v,i+1));
                    }
                    else{
                        x.add(datos.get(i));
                    }

                    if(x.get(i)<0){
                        x.set(i, 0.0);
                    }
                }
//                System.out.println("x : "+x);
                int p = size-first_size;
                int sx= x.size();
                nx.addAll(x.subList(p, x.size()));

  //              System.out.println("nx :"+nx);
   //             System.out.println("size nx : "+nx.size());
                clearAll();
                datos=clearDatos(datos);
                //datos.clear();


            }

        }
        //	double val =0;
        //for(int i=0; i<sized; i++){
        //		val+=(Q.)
//		}
        return nx;

    }

    private SimpleMatrix reverse(SimpleMatrix v) {
        // TODO Auto-generated method stub
        SimpleMatrix rpta = new SimpleMatrix(v.numRows(), v.numCols());

        for(int i=v.numCols()-1, j=0; i>=0; i--, j++){
            rpta.set(0,j , v.get(0, i));
        }

        return rpta;
    }
    private void clearAll() {
        // TODO Auto-generated method stub
        x.clear();
        indices.clear();
        //datos.clear();
        y.clear();

    }
    private Vector<Double> clearDatos(Vector<Double> v){
        v.clear();
        Vector<Double> nv = new Vector<Double>(n_interval);
        v=nv;
        v=iniVector(v);
        return v;
    }

    private Vector<Double> iniVector(Vector<Double> v){
        for (int i = 0; i < v.capacity(); i++) {
            v.add(0.0);
        }
        return v;
    }

    private SimpleMatrix vector2SimpleMatrix (Vector<Double> v){
        SimpleMatrix rpta = new SimpleMatrix(1,v.size());
        for (int i = 0; i < v.size(); i++) {
            rpta.set(0,i,v.get(i));
        }
        return rpta;

    }



    private Double polyVal(SimpleMatrix v, int x) {
        // TODO Auto-generated method stub
        double val =0.0;

        for(int i=0; i<v.numRows(); i++){
            for(int j=0; j<v.numCols(); j++){
                val+=v.get(i, j)*Math.pow(x,(v.numCols()-1)-j);
            }

        }
        return val;

    }

    private SimpleMatrix poly(Integer nFaltantes,Vector<Integer> indices2) {
        // TODO Auto-generated method stub
        int size= indices2.size();

    //    System.out.println("indices : "+indices2);
    //    System.out.println("faltantes : "+nFaltantes);

        SimpleMatrix M = new SimpleMatrix(size,nFaltantes+1);

        for(int k=0; k<size; k++){
            for(int i=0; i<=nFaltantes; i++){
                M.set(k, i, Math.pow(indices2.get(k)+1,i));
            }
        }


        //System.out.println(M.get(0, 0));
        //M.print();
        return M;
    }


    private Vector<Double> recreateData(Vector<Double> datosf,Vector<Double> datos2, int indice) {
        // TODO Auto-generated method stub

        int n_validos =2;
        int cont =0;
        int indice_valido =0;
        //System.out.println("datos2 "+datos2);

        if(datos2.get(0)==999999 && indice!=0){
            for(int i=indice; i==0 ; i--){
                if(datosf.get(i)!=999999){
                    for(int j=1; j<n_validos; j++){
                        if(datosf.get(i-j)!=999999){
                            cont++;
                        }
                        else{
                            break;
                        }
                    }
                    indice_valido=i;
                    break;
                }
            }
            datos2.addAll(0,datosf.subList(indice_valido-cont, indice-1));
        }

        return datos2;
    }


    public static Vector<Double> readFile(String name){
        Vector<Double> Qf = new Vector<Double>();
        File archivo = null;
        FileReader fr = null;
        BufferedReader br = null;

        try {
            archivo = new File (name);
            fr = new FileReader (archivo);
            br = new BufferedReader(fr);

            String linea;

            while((linea=br.readLine())!=null){

                String []valores=linea.split("\\s+");

                for(String s : valores){
                    if(s.equals("NaN")){
                        Qf.add(null);
                    }else{
                        Qf.add(Double.parseDouble(s));
                    }
                }

            }

        }
        catch(Exception e){
            e.printStackTrace();
        }
        try{
            if( null != fr ){
                fr.close();
            }
        }catch (Exception e2){
            e2.printStackTrace();

        }

        return Qf;
    }


}


